package com.jiuyue.movehouse.common.handler;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.SimplePropertyPreFilter;

import com.jiuyue.movehouse.annotion.JsonFilter;
import com.jiuyue.movehouse.annotion.NotResponseBody;
import com.jiuyue.movehouse.common.exception.BadRequestException;
import com.jiuyue.movehouse.utils.ThrowableUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * @author min
 * @description
 * @date 2021/1/18
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionResultHandler implements ResponseBodyAdvice<Object> {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        String massage = "";
        for (ObjectError error : e.getBindingResult().getAllErrors()) {
            massage += (error.getDefaultMessage() + ";");
        }
        return new R<>(ResultCode.PARAMS_ERROR).setMessage(massage);
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Object httpMessageNotReadableExceptionHandler(HttpMessageNotReadableException e) {
        return new R<>(ResultCode.ERROR).setMessage(e.getMessage());
    }

    @ExceptionHandler(BadRequestException.class)
    public Object badRequestExceptionHandler(BadRequestException e) {

        return new R<>(e.getResultCode()==null?ResultCode.ERROR:e.getResultCode()).setMessage(e.getMessage());
    }


    /**
     * 处理所有不可知的异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public R handleException(Exception e) {
        // 打印堆栈信息
        // 打印堆栈信息
        log.error(e.getClass().getName());
        log.error(e.getMessage());
        log.error(ThrowableUtil.getStackTrace(e));
        return new R(ResultCode.UNKNOW_ERROR).setMessage(e.getStackTrace()[0].getClassName()
                + " " + e.getStackTrace()[0].getLineNumber()
                + "行 " + e.getClass().getName()
                + " " + e.getMessage());
    }


    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return !methodParameter.getParameterType().equals(R.class) && !methodParameter.hasMethodAnnotation(NotResponseBody.class);
    }

    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        if (methodParameter.hasMethodAnnotation(JsonFilter.class)) {
            return new R<>(this.filterField(o, methodParameter));
        }
        return new R<>(o);
    }

    private Object filterField(Object o, MethodParameter methodParameter) {
        JsonFilter jsonFilter = methodParameter.getMethodAnnotation(JsonFilter.class);
        SimplePropertyPreFilter filter = new SimplePropertyPreFilter();
        for (String column : jsonFilter.excludes()) {
            filter.getExcludes().add(column);
        }
        for (String column : jsonFilter.includes()) {
            filter.getIncludes().add(column);
        }
//        fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
        Object result = JSONObject.parse(JSONObject.toJSONString(o, filter,
                SerializerFeature.WriteMapNullValue,
                SerializerFeature.DisableCircularReferenceDetect,
                SerializerFeature.WriteDateUseDateFormat,
                SerializerFeature.WriteNullListAsEmpty));
        return result;
    }
}
